from django.shortcuts import render
from rest_framework.views import APIView
from django_redis import get_redis_connection
import pickle
import base64
from rest_framework.response import Response
from rest_framework import status

from goods.models import SKU
from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer, CartSelectAllSerializer
from . import constants

# Create your views here.


class CartView(APIView):
    """
    购物车
    """
    def perform_authentication(self, request):
        """重写父类的用户验证方法，不在进入视图前就检查JWT"""
        pass

    def post(self, request):
        """
        添加到购物车
        POST /cart/
        """
        # 获取请求参数
        data = request.data
        # 序列化检验
        s = CartSerializer(data=data)
        s.is_valid(raise_exception=True)
        sku_id = s.validated_data['sku_id']
        count = s.validated_data['count']
        selected = s.validated_data['selected']

        # 判断用户的登录状态
        try:
            user = request.user     # 可能是AnonymoseUser 匿名用户
        except Exception:
            # 前端携带了错误的JWT
            user = None

        if user and user.is_authenticated:
            # 如果登录，保存到redis 中
            # {
            #     1001: {
            #         1: 5,
            #         2: 3
            #     }哈希类型
            # }
            # {
            #     1001： {1,2,3...}集合类型
            # }
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()

            # 记录购物车商品数量
            pl.hincrby('cart_%s' % user.id, sku_id, count)
            # 记录商品的勾选状态,如果勾选，添加
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            pl.execute()

            return Response(s.data)
        else:
            # 如果不登录，保存到cookie中

            # 使用pickle序列化购物车数据，pickle操作的是bytes类型
            cart_cookie = request.COOKIES.get('cart')
            # {
            #     1001: { "count": 10, "selected": true},
            #     ...
            # }
            if cart_cookie:
                # 解析
                cart = cart_cookie.encode()
                cart = base64.b64decode(cart)
                cart = pickle.loads(cart)
            else:
                cart = {}

            if sku_id in cart.keys():
                # 如果商品在购物车中，累加
                cart[sku_id]['count'] += count
                cart[sku_id]['selected'] = selected
            else:
                # 如果商品不在购物车中，设置
                cart[sku_id] = {
                    'count': count,
                    'selected': selected
                }

            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()

            # 设置cookie
            response = Response(s.data)
            response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)

            return response

    def get(self, request):
        """
        获取购物车数据
        GET /cart/
        """
        # [
        #     {
        #         "id": 9,
        #         "count": 3,
        #         "name": "华为 HUAWEI P10 Plus 6GB+64GB 钻雕金 移动联通电信4G手机 双卡双待",
        #         "default_image_url": "http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrRcUeAHp9pAARfIK95am88523545",
        #         "price": "3388.00",
        #         "selected": true
        #     },
        #     ...
        # ]
        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 如果登录，从redis中取到购物车数据
            redis_conn = get_redis_connection('cart')
            sku_count = redis_conn.hgetall('cart_%s' % user.id)
            selected = redis_conn.smembers('cart_selected_%s' % user.id)
            # sku_count = {
            #     商品的sku_id: 数量(都是bytes字节类型)
            #     ....
            # }
            # selected = set(商品的sku_id, .....)  (bytes字节类型)
            cart = {}

            for sku_id, count in sku_count.items():
                cart[int(sku_id)] = {
                    'count': int(count),
                    # 判断sku_id是否在selected中，结果为true或false
                    'selected': sku_id in selected
                }
        else:
            # 如果未登录，从cookie中取到购物车数据
            cart_cookie = request.COOKIES.get('cart')
            if cart_cookie:
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))
            else:
                cart = {}

        # 遍历购物车数据
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        s = CartSKUSerializer(skus, many=True)
        return Response(s.data)

    def put(self, request):
        """
        修改购物车数据
        PUT /cart/
        """
        s = CartSerializer(data=request.data)
        s.is_valid(raise_exception=True)
        sku_id = s.validated_data['sku_id']
        count = s.validated_data['count']
        selected = s.validated_data['selected']

        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 如果登录，修改redis中的数据
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hset('cart_%s' % user.id, sku_id, count)
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()

            return Response(s.data)
        else:
            # 如果未登录，修改cookie中的数据
            cart_cookie = request.COOKIES.get('cart')
            if cart_cookie:
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))
            else:
                cart = {}

            response = Response(s.data)

            if sku_id in cart:
                cart[sku_id] = {
                    'count': count,
                    'selected': selected
                }

                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('cart', cookie_cart, constants.CART_COOKIE_EXPIRES)

            return response

    def delete(self, request):
        """
        删除购物车数据
        DELETE /cart/
        """
        s = CartDeleteSerializer(data=request.data)
        s.is_valid(raise_exception=True)
        sku_id = s.validated_data['sku_id']

        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 如果登录，删除redis中数据
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 删除数量
            pl.hdel('cart_%s' % user.id, sku_id)
            # 删除勾选状态
            pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()

            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 如果未登录，删除cookie中数据
            response = Response(status=status.HTTP_204_NO_CONTENT)

            cart_cookie = request.COOKIES.get('cart')
            if cart_cookie:
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))
                if sku_id in cart:
                    del cart[sku_id]

                    cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                    response.set_cookie('cart', cookie_cart, constants.CART_COOKIE_EXPIRES)

            return response


class CartSelectAllView(APIView):
    """
    购物车全选
    """
    def perform_authentication(self, request):
        pass

    def put(self, request):
        """
        设置全选
        PUT /cart/selection/
        """
        s = CartSelectAllSerializer(data=request.data)
        s.is_valid(raise_exception=True)
        selected = s.validated_data['selected']

        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            redis_conn = get_redis_connection('cart')
            cart = redis_conn.hgetall('cart_%s' % user.id)
            sku_id_list = cart.keys()

            if selected:
                # 全选
                redis_conn.sadd('cart_selected_%s' % user.id, *sku_id_list)
            else:
                # 取消全选
                redis_conn.srem('cart_selected_%s' % user.id, *sku_id_list)

            return Response({'message': 'OK'})
        else:
            cart_cookie = request.COOKIES.get('cart')
            response = Response({'message': 'OK'})

            if cart_cookie:
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))
                for sku_id in cart:
                    cart[sku_id]['selected'] = selected

                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('cart', cookie_cart, constants.CART_COOKIE_EXPIRES)

            return response

